"""@package tagengine.objects
The object classes for the TAG Engine

This module contains the base classes for all game objects"""

from tagengine.commons import *
from tagengine.constants import *
import logging
logger = logging.getLogger("tagengine.objects")

class BaseObject(object):
    """Base object for all game objects. 
    
    This class creates a skeleton for all game objects. Acts as a base framework.
    It provides some common methods.""" 
    
    def connect(self):
        """Connects the objects with other objects. 
        
        This function requires self.data and self.game to be set in order to loop through and associate with the game."""
        for key in self.data:
            if self.data[key].type == "varname":
                l = []
                for var in self.data[key].value:
                    try:
                        l.append(getattr(self.game, var))
                    except AttributeError:
                        logger.critical("The varname %s is not found under the game." % var)
                        raise AttributeError("The varname %s is not found under the game." % var)
                
                setattr(self, key, l)
            elif self.data[key].type == "trigger":
                try:
                    if self.data[key].value:
                        setattr(self, key, getattr(self.game.triggers, self.data[key].value))
                    else:
                        setattr(self, key, self.game.triggers.dummyTrigger)
                except AttributeError as e:
                    logger.critical("Trigger '%s' not found." % self.data[key].value)
                    raise e
            else:
                setattr(self, key, self.data[key].value)
        
        if hasattr(self, "location"):
            self.location = self.location[0]
        logger.info("Connected %s %s with world." % (self.__class__.__name__, self.name))

    def _buildTriggerArgument(self, indirectObj=None, **keywords):
        """Shortcut functions to construct a trigger argument with dictionary. 
        
        This function ensures that some of the common arguments are provided.
        @param indirectObj The indirect object."""
        
        args = dict()
        if self.type == Constants.ITEM_TYPE:
            args["item"] = self
        elif self.type == Constants.CHARACTER_TYPE:
            args["character"] = self
            
        args["game"] = self.game
        args["indirect_object"] = indirectObj
        args["iobj"] = indirectObj
        args["player"] = self.game.player
        args.update(keywords)
        return LockedDictionary(args)
    
    def __repr__(self):
        return "<%s: %s>" % (self.__class__.__name__, self.varname)

class InteractableObject(BaseObject):
    """A base class for objects that can be interacted by the players.
    
    This provides additional methods for the class."""
    def inRoom(self, room, recursive=False):
        """A function that checks whether if this object is in a certain room.
        
        @param room An instance of a room that you want to check if the item is in.
        @param recursive A boolean value indicates whether if you want to continuously check the parent location until it encounters a room (If your item is in a bag in a room, this would be useful)
        """
        if recursive:
            if self.location.type != Constants.ROOM_TYPE:
                return self.inRoom(room, True)
        return self.location == room and self in room.inventory
    
    def sameRoomAsPlayer(self, recursive=False):
        """ Check if the Item is in the same room as the player. 
        
        @param recursive if recursive is set to true, this function will return the object in the same room as player if the object is in the same room, other wise it returns true and false."""
        if recursive:
            if self.location.type != Constants.ROOM_TYPE:
                if self.location.type == Constants.ITEM_TYPE:
                    return self.location.sameRoomAsPlayer(True) and self.location.openable == 2
                else:
                    return self.location.sameRoomAsPlayer(True)
        
        if self.location == self.game.player.location:
            if recursive: 
                return self
            else: 
                return True
        else:
            return False